package com.smartian.scan.filesearch.bean;

import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;

public class TreeNodeFile {


    public static final int TYPE_ROOT       = 0x000;
    public static final int TYPE_LEAF       = 0x001;
    private static final int TYPE_BRANCH    = 0x010;

    private String pathName;
    private List<TreeNodeFile> children;
    private int type;
    private int deep;
    private TreeNodeFile parent;
    private String fullPath;
    private boolean isFileRegExp = false;

    public TreeNodeFile getParent() {
        return parent;
    }

    public TreeNodeFile(){
        type = TYPE_ROOT;
        pathName = "/";
    }


    public boolean isFileRegExp() {
        return isFileRegExp;
    }

    public void buildTree(List<String> pathlist){

        TreeNodeFile appleTreeRoot = new TreeNodeFile();

        if(pathlist==null) return;

        for (int i=0;i<pathlist.size();i++) {

            Stack<String> stack = new Stack<String>();
            String strPath = pathlist.get(i);

            String fullPath = getFormatPath(strPath);

            stack.push(fullPath);

            TreeNodeFile parent = this;
            int deep = 1;

            do {
                if (stack.empty()) break;

                if(parent.type==TYPE_LEAF) break;

                String path = stack.pop();
                int firstIndex = path.indexOf(File.separator);
                String childPath = null;

                int type = -1;
                boolean isRegexFileName  = false;

                if (firstIndex == -1) {
                     childPath = path;
                     type = TYPE_LEAF;
                }else  if(firstIndex==0){
                    //说明存在正则路径
                    if(path.length()>2) {
                        String regexPath = path.substring(2);
                        firstIndex = regexPath.indexOf(File.separator);
                        if(firstIndex!=-1) {
                            type = TYPE_BRANCH;
                            childPath = regexPath.substring(0, firstIndex);
                            path = regexPath;
                        }else{
                            childPath = regexPath;
                            type = TYPE_LEAF;
                        }

                    }else{
                        continue;
                    }
                } else if(firstIndex==1 && path.charAt(0)=='+'){

                    if(path.length()>2) {
                        childPath = path.substring(2);
                        isRegexFileName = true;
                        type = TYPE_LEAF;
                    }else{
                        continue;
                    }
                }else{
                    childPath = path.substring(0, firstIndex);

                    if(path.length()>firstIndex+1) {
                        type = TYPE_BRANCH;
                    }else{
                        type = TYPE_LEAF;
                    }
                }

                if(stringIsEmptyOrNull(childPath)) continue;

                TreeNodeFile appTree = createTreeFile(parent, deep, childPath, type, isRegexFileName);
                parent = appTree;

                if(parent.type==TYPE_LEAF){
                    parent.cleanChildren();
                    continue;
                }

                if(path.length()>firstIndex+1) {
                    stack.push(path.substring(firstIndex + 1));
                }

                deep++;

            } while (true);
        }

    }

    private TreeNodeFile createTreeFile(TreeNodeFile parent, int deep, String childPath, int type , boolean isRegexFileName) {
        TreeNodeFile appTree = parent.getTreeFile(childPath);
        appTree.type = type;
        appTree.deep = deep;
        appTree.isFileRegExp = isRegexFileName;

        parent.addChild(appTree);
        appTree.setParent(parent);
        return appTree;
    }

    private void setParent(TreeNodeFile parent) {
        this.parent = parent;
    }



    private void cleanChildren() {
        if(children==null) return;
        children.clear();
    }

    private boolean stringIsEmptyOrNull(String text) {
        return text==null ||text.length()==0;
    }

    public void printTree(){

        Queue<TreeNodeFile> queue = new LinkedBlockingQueue<>();
        queue.offer(this);
        System.out.print(String.format("{%s,%d}",this.pathName,this.type));
        int deep = 0;
        do{
            if(queue.isEmpty()){
                break;
            }
            TreeNodeFile treeFile = queue.poll();

            List<TreeNodeFile> children = treeFile.getChildren();
            if(children==null || children.size()==0) continue;
            for (TreeNodeFile t: children){
                queue.offer(t);
                if(t.deep>deep) {
                    deep = t.deep;
                    System.out.println();
                }

                System.out.print(String.format("{%s,%d}",t.pathName,t.type));
            }

        }while (true);
    }

    public int getTreeHeight(TreeNodeFile tree){

        if(tree==null) return 0;
        List<TreeNodeFile> children = tree.getChildren();
        if(children==null || children.size()==0) return 1;
        int height = 1;
        for (int i=0;i<children.size();i++){
            height = Math.max(getTreeHeight(children.get(i))+1,height);
        }
        return height;

    }

    public void printTreeHeight( ){
        System.out.println();
        System.out.println("深度："+getTreeHeight(this));

    }


    public List<TreeNodeFile> getChildren() {
        return children;
    }

    private String getFormatPath(String strPath) {
        String fullpath = strPath.trim();
        if(fullpath.endsWith(File.separator)){
            fullpath = fullpath.substring(0,fullpath.length()-1);
        }
        if(fullpath.startsWith(File.separator)){
            fullpath = fullpath.substring(1);
        }
        return fullpath;
    }

    public TreeNodeFile getTreeFile(String path) {
        TreeNodeFile appTree =  findTreeFile(path);

        if(appTree==null) {
            appTree = new TreeNodeFile();
            appTree.pathName = path;
        }
        return appTree;
    }

    public TreeNodeFile findTreeFile(String pathName) {
        if(children==null){
            return null;
        }
        for (TreeNodeFile child : children){

            if(pathName.equals(child.pathName)){
                return child;
            }
        }
        return null;
    }

    public void addChild(TreeNodeFile appTree) {
        if(appTree==null) return;

        if(children==null){
            children = new LinkedList<>();
        }
        if(children.contains(appTree)) return;
         children.add(appTree);
    }

    public void addChild(String pathName) {
        TreeNodeFile treeFile =  getTreeFile(pathName);
        addChild(treeFile);
    }


    public static void main(String[] args) {
        TreeNodeFile treeFile = new TreeNodeFile();
        treeFile.buildTree(Arrays.asList(PATHS));
        treeFile.printTree();

        treeFile.printTreeHeight();
    }
    public static final String[] PATHS = {
           /* "/Users/tianweitong/Downloads",
            "/Users/tianweitong/Library/[a-zA-Z0-9_\\-]{1,}",
            "/Users/tianweitong/GitRespo/[a-zA-Z0-9_\\-]{1,}/[a-zA-Z0-9_\\-]{1,}/src",
            "/Users/tianweitong/Desktop/testFiles/+/gc_//d{4}.png",*/

            "/storage/emulated/0/tencent/MicroMsg/weixin/+/wx_camera_[0-9]{1,}.jpg",
            "/storage/emulated/0/tencent/MicroMsg/weixin/+/mmexport[0-9]{1,}.jpg",
            "/storage/emulated/0/tencent/MicroMsg//[a-zA-Z0-9]{32}/image2/+/[0-9a-zA-Z]{32}.jpg",
            "/storage/emulated/0/tencent/MicroMsg//[a-zA-Z0-9]{32}/image2/+/th_[0-9a-zA-Z]{32,}",
            "/storage/emulated/0/tencent/MicroMsg//[a-zA-Z0-9]{32}/image2/[0-9a-zA-Z]{2}/[0-9a-zA-Z]{2}/+/[0-9a-zA-Z]{32,}.jpg",
            "/storage/emulated/0/tencent/MicroMsg//[a-zA-Z0-9]{32}/image2/[0-9a-zA-Z]{2}/[0-9a-zA-Z]{2}/+/th_[0-9a-zA-Z]{32,}",

            "/storage/emulated/0/Android/data/com.tencent.mm/MicroMsg//[a-zA-Z0-9]{32}/image2/[0-9a-zA-Z]{2}/[0-9a-zA-Z]{2}/+/[0-9a-zA-Z]+.png",
            "/storage/emulated/0/Android/data/com.tencent.mm//MicroMsg/[a-zA-Z0-9]{32}/image2/+/[0-9a-zA-Z]{1,}",
            "/storage/emulated/0/Android/data/com.tencent.mm/MicroMsg//[a-zA-Z0-9]{32}/video/+/vsg_output_[0-9]{1,}",
            "/storage/emulated/0/Android/data/com.tencent.mm/MicroMsg//[a-zA-Z0-9]{32}/image2/[0-9a-zA-Z]{2}/[0-9a-zA-Z]{2}/+/[0-9a-zA-Z]+",
            "/storage/emulated/0/Android/data/com.tencent.mm/MicroMsg//[a-zA-Z0-9]{32}/video/+/video_thumb_[0-9]{1,}"
    };


    public String getFullPath() {

        if(!stringIsEmptyOrNull(this.fullPath))  return this.fullPath;

        StringBuilder sb = new StringBuilder();
        sb.append(this.pathName);
        TreeNodeFile parent = getParent();
        do{
           if(parent==null) break;
           String path = parent.getPathName();

           sb.insert(0,File.separator);

           if(parent.type==TYPE_ROOT) break;

            sb.insert(0,path);
            parent = parent.getParent();
        }while (true);

        this.fullPath =  sb.toString();

        return this.fullPath;
    }

    public String getPathName() {
        return pathName;
    }

    public int getType() {
        return type;
    }


}
